/**
 * Copyright (c) 2013-2022 Nikita Koksharov
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.redisson.config;

import org.redisson.connection.balancer.LoadBalancer;
import org.redisson.connection.balancer.RoundRobinLoadBalancer;

/**
 * 主从服务器配置基类
 */
public class BaseMasterSlaveServersConfig<T extends BaseMasterSlaveServersConfig<T>> extends BaseConfig<T> {

    /**
     * 初始化负载均衡器为轮询算法。
     * 这是一个私有成员变量，用于在类内部实现负载均衡功能。
     * 通过实例化一个轮询算法的负载均衡器 {@link RoundRobinLoadBalancer} 来实现。
     */
    private LoadBalancer loadBalancer = new RoundRobinLoadBalancer();

    /**
     * 从节点连接最小空闲大小为24
     * 此变量控制着与从服务器保持的最小活跃连接数，以确保在需要时可以立即使用这些连接。
     */
    private int slaveConnectionMinimumIdleSize = 24;

    /**
     * 从节点连接池大小,默认值64
     * 此变量控制着与从服务器保持的最大连接数，以适应负载均衡器的负载均衡策略。
     */
    private int slaveConnectionPoolSize = 64;

    /**
     * 从节点失败重连时间间隔，默认值3000毫秒
     * 此变量控制着从服务器失败后，多久再次尝试连接。
     */
    private int failedSlaveReconnectionInterval = 3000;

    /**
     * 从节点失败检测时间间隔，默认值30000毫秒
     * 此变量控制着从服务器失败检测的时间间隔。
     */
    private int failedSlaveCheckInterval = 180000;

    /**
     * 主节点连接最小空闲大小为24
     * 此变量控制着与主服务器保持的最小活跃连接数，以确保在需要时可以立即使用这些连接。
     */
    private int masterConnectionMinimumIdleSize = 24;

    /**
     * 主节点连接池大小,默认值64
     * 此变量控制着与主服务器保持的最大连接数，以适应负载均衡器的负载均衡策略。
     */
    private int masterConnectionPoolSize = 64;


    /**
     * 默认的读取模式设置为从SLAVE读取。
     * 这是一个私有成员变量，用于在类内部指定数据读取的模式。
     * ReadMode是一个枚举类型，这里它的默认值被设置为SLAVE，表示系统默认从从服务器（Slave）进行读取操作。
     */
    private ReadMode readMode = ReadMode.SLAVE;

    /**
     * 订阅模式变量，默认为MASTER模式。
     * 这个变量定义了客户端在订阅服务时的行为模式。
     * SubscriptionMode是一个枚举类型，包括MASTER和SLAVE两种模式。
     * MASTER模式表示客户端将作为主订阅者，而SLAVE模式表示客户端将作为从订阅者。
     */
    private SubscriptionMode subscriptionMode = SubscriptionMode.MASTER;


    /**
     * 此变量定义了Redis 'slave'节点中，每个节点的最小空闲订阅（pub/sub）连接数量。
     * 这个设置可以保证每个slave节点至少有指定数量的连接可用于订阅和发布消息。
     *
     * @return int 返回每个slave节点的最小空闲订阅连接数量。
     */
    private int subscriptionConnectionMinimumIdleSize = 1;


    /**
     * 此变量定义了Redis 'slave'节点的最大订阅（pub/sub）连接池大小。
     * 这个设置针对的是每个slave节点，而不是整个集群中的所有slave节点。
     * 增加这个值可以提高系统处理大量订阅者的能力，但也会消耗更多的系统资源。
     * 默认值为50，可以根据实际系统负载和资源情况进行调整。
     */
    private int subscriptionConnectionPoolSize = 50;


    /**
     * dnsMonitoringInterval 常量定义了DNS监控的间隔时间。
     * 这个变量决定了程序对DNS进行监控的时间频率，单位为毫秒。
     * 默认值为5000毫秒，即每5秒进行一次DNS监控。
     */
    private long dnsMonitoringInterval = 5000;


    public BaseMasterSlaveServersConfig() {
    }

    BaseMasterSlaveServersConfig(T config) {
        super(config);
        setLoadBalancer(config.getLoadBalancer());
        setMasterConnectionPoolSize(config.getMasterConnectionPoolSize());
        setSlaveConnectionPoolSize(config.getSlaveConnectionPoolSize());
        setSubscriptionConnectionPoolSize(config.getSubscriptionConnectionPoolSize());
        setMasterConnectionMinimumIdleSize(config.getMasterConnectionMinimumIdleSize());
        setSlaveConnectionMinimumIdleSize(config.getSlaveConnectionMinimumIdleSize());
        setSubscriptionConnectionMinimumIdleSize(config.getSubscriptionConnectionMinimumIdleSize());
        setReadMode(config.getReadMode());
        setSubscriptionMode(config.getSubscriptionMode());
        setDnsMonitoringInterval(config.getDnsMonitoringInterval());
        setFailedSlaveCheckInterval(config.getFailedSlaveCheckInterval());
        setFailedSlaveReconnectionInterval(config.getFailedSlaveReconnectionInterval());
    }


    public T setSlaveConnectionPoolSize(int slaveConnectionPoolSize) {
        this.slaveConnectionPoolSize = slaveConnectionPoolSize;
        return (T) this;
    }

    public int getSlaveConnectionPoolSize() {
        return slaveConnectionPoolSize;
    }


    public T setFailedSlaveReconnectionInterval(int failedSlavesReconnectionTimeout) {
        this.failedSlaveReconnectionInterval = failedSlavesReconnectionTimeout;
        return (T) this;
    }

    public int getFailedSlaveReconnectionInterval() {
        return failedSlaveReconnectionInterval;
    }


    public T setFailedSlaveCheckInterval(int slaveFailsInterval) {
        this.failedSlaveCheckInterval = slaveFailsInterval;
        return (T) this;
    }

    public int getFailedSlaveCheckInterval() {
        return failedSlaveCheckInterval;
    }

    public T setMasterConnectionPoolSize(int masterConnectionPoolSize) {
        this.masterConnectionPoolSize = masterConnectionPoolSize;
        return (T) this;
    }

    public int getMasterConnectionPoolSize() {
        return masterConnectionPoolSize;
    }


    public T setLoadBalancer(LoadBalancer loadBalancer) {
        this.loadBalancer = loadBalancer;
        return (T) this;
    }

    public LoadBalancer getLoadBalancer() {
        return loadBalancer;
    }


    public T setSubscriptionConnectionPoolSize(int subscriptionConnectionPoolSize) {
        this.subscriptionConnectionPoolSize = subscriptionConnectionPoolSize;
        return (T) this;
    }

    public int getSubscriptionConnectionPoolSize() {
        return subscriptionConnectionPoolSize;
    }


    public T setSlaveConnectionMinimumIdleSize(int slaveConnectionMinimumIdleSize) {
        this.slaveConnectionMinimumIdleSize = slaveConnectionMinimumIdleSize;
        return (T) this;
    }

    public int getSlaveConnectionMinimumIdleSize() {
        return slaveConnectionMinimumIdleSize;
    }


    public T setMasterConnectionMinimumIdleSize(int masterConnectionMinimumIdleSize) {
        this.masterConnectionMinimumIdleSize = masterConnectionMinimumIdleSize;
        return (T) this;
    }

    public int getMasterConnectionMinimumIdleSize() {
        return masterConnectionMinimumIdleSize;
    }


    public T setSubscriptionConnectionMinimumIdleSize(int subscriptionConnectionMinimumIdleSize) {
        this.subscriptionConnectionMinimumIdleSize = subscriptionConnectionMinimumIdleSize;
        return (T) this;
    }

    public int getSubscriptionConnectionMinimumIdleSize() {
        return subscriptionConnectionMinimumIdleSize;
    }


    public T setReadMode(ReadMode readMode) {
        this.readMode = readMode;
        return (T) this;
    }

    public ReadMode getReadMode() {
        return readMode;
    }

    public boolean isSlaveNotUsed() {
        return getReadMode() == ReadMode.MASTER && getSubscriptionMode() == SubscriptionMode.MASTER;
    }


    public T setSubscriptionMode(SubscriptionMode subscriptionMode) {
        this.subscriptionMode = subscriptionMode;
        return (T) this;
    }

    public SubscriptionMode getSubscriptionMode() {
        return subscriptionMode;
    }


    public T setDnsMonitoringInterval(long dnsMonitoringInterval) {
        this.dnsMonitoringInterval = dnsMonitoringInterval;
        return (T) this;
    }

    public long getDnsMonitoringInterval() {
        return dnsMonitoringInterval;
    }

}
